﻿using MaterialDesignThemes.Wpf;
using Prism.Commands;
using Prism.Events;
using Prism.Ioc;
using Prism.Modularity;
using StarryEdge.Core;
using StarryEdge.Core.Manager;
using StarryEdge.Core.Parameter;
using StarryEdge.Core.Plugin;
using StarryEdge.Domains;
using StarryEdge.Menu.Device;
using StarryEdge.Model;
using StarryEdge.Parameter;
using StarryEdge.WPF.Attributes;
using StarryEdge.WPF.Lang;
using StarryEdge.WPF.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Xml.Linq;

namespace StarryEdge.ViewModels
{
    public class EnumTreeViewModel
    {
        private List<MenuAssemblyModel> menuAssemblyModels = new List<MenuAssemblyModel>();
        public ObservableCollection<StarryEdge.WPF.Models.MenuModel> Menus { get; set; }
        private IEventAggregator _aggregator;
        private IContainerExtension _containerExtension;
        private IUIRoleManage _roleManage;
        public EnumTreeViewModel(IContainerExtension containerExtension, IEventAggregator aggregator, IUIRoleManage roleManage)
        {
            _roleManage = roleManage;
            _containerExtension = containerExtension;
            _aggregator = aggregator;
            aggregator.GetEvent<MessageEvent>().Subscribe(sender => {
                foreach (var item in Menus)
                {
                    item.Title = LangManager.Instance.Lang[item.TitleLang];
                    foreach (var children in item.Childrens)
                    {
                        children.Update();
                    }
                }
            }, arg => arg.Code == 210);
            aggregator.GetEvent<MessageEvent>().Subscribe(sender => Update(), arg => arg.Code == 230);
            Menus = new ObservableCollection<WPF.Models.MenuModel>();
            Init();
            _ = containerExtension.Resolve<IPluginManager>().LoadDll();
            aggregator.GetEvent<MessageEvent>().Subscribe(sender => {
                if (!string.IsNullOrEmpty(sender.Message))
                {
                    string[] strings = sender.Message.Split('_');
                    StarryEdge.WPF.Models.MenuModel menu = Menus.FirstOrDefault(x => x.TitleLang == strings[0]);
                    if (menu != null)
                    {
                        MenuItemModel menuitem = menu.Childrens.FirstOrDefault(x => x.Name == strings[1]);
                        OpenView(menuitem);
                    }
                }
            }, arg => arg.Code == 220);

            DisplayFirstView(false);
        }

        private void DisplayFirstView(bool isOne = true)
        {
            if (Menus.Count > 0 && Menus[0].Childrens.Count > 0)
            {
                OpenView(Menus[0].Childrens[0], isOne);
            }
        }

        private object _oldView;
        private void OpenView(MenuItemModel menu, bool isOne = true)
        {
            try
            {
                if (isOne)
                {
                    var loginuser = _containerExtension.Resolve<IUserEntity>().GetLoginUser();
                    if (loginuser == null && _containerExtension.Resolve<IDialogHost>() is IDialogHost dialogHost)
                    {
                        dialogHost.DialogShow(LangManager.Instance.ToolTip["UnloggedAccount"], Core.Enums.LogLevel.Warning, hostDialog : Core.Enums.PopUpTypes.Global);
                        return;
                    }
                }
                if (menu != null && menu.View != null && menu.ViewModel != null)
                {
                    if (_oldView is System.Windows.Controls.UserControl user && user.DataContext is IViewModelLife life)
                    {
                        try
                        {
                            life.Exit();
                        }
                        catch (Exception ex)
                        {
                            _containerExtension.Resolve<IDialogHost>()?.DialogShow($"{menu.ViewModel.Name}视图退出事件异常：{ex}", Core.Enums.LogLevel.Warning);
                        }
                    }
                    UserControl userControl = Activator.CreateInstance(menu.View) as System.Windows.Controls.UserControl;
                    List<object> plist = new();
                    var ps = menu.ViewModel.GetConstructors()[^1].GetParameters();
                    foreach (var p in ps)
                    {
                        plist.Add(_containerExtension.Resolve(p.ParameterType));
                    }
                    userControl.DataContext = Activator.CreateInstance(menu.ViewModel, plist.ToArray());
                    try
                    {
                        if (userControl.DataContext is IViewModelLife life1)
                        {
                            life1.Enter();
                        }
                    }
                    catch (Exception ex)
                    {
                        _containerExtension.Resolve<IDialogHost>()?.DialogShow($"{menu.ViewModel.Name}视图退出事件异常：{ex}", Core.Enums.LogLevel.Warning);
                    }
                    _oldView = userControl;
                    MessageEventModel message = new MessageEventModel
                    {
                        Code = 200,
                        Message = "View",
                        Data = new Dictionary<string, object>() { { "View", userControl } }
                    };
                    _aggregator.GetEvent<MessageEvent>().Publish(message);
                }
            }
            catch (Exception ex)
            {
                _containerExtension.Resolve<IDialogHost>().DialogShow($"打开视图异常：{ex}", Core.Enums.LogLevel.Error, hostDialog: Core.Enums.PopUpTypes.Global);
            }
        }

        public DelegateCommand<TreeView> SelectedItemChanged => new DelegateCommand<TreeView>(sender =>
        {
            MenuItemModel menu = sender.SelectedItem as MenuItemModel;
            OpenView(menu);
        });

        /// <summary>
        /// 初始化菜单
        /// </summary>
        private void Init()
        {
            if (menuAssemblyModels.Count == 0)
            {
                List<Type> types = new List<Type>();
                var dlls = AssemblyLoadContext.All;
                foreach (var dll in dlls)
                {
                    foreach (var assemblie in dll.Assemblies)
                    {
                        try
                        {
                            var parameter = assemblie.GetTypes().Where(t => t.IsClass && typeof(IModule).IsAssignableFrom(t) && typeof(StarryEdge.WPF.Models.MenuModel).IsAssignableFrom(t)).ToList();
                            if (parameter.Count > 0)
                            {
                                StarryEdge.WPF.Models.MenuModel menuModel = Activator.CreateInstance(parameter[0]) as StarryEdge.WPF.Models.MenuModel;
                                menuModel.Childrens = new ObservableCollection<WPF.Models.MenuItemModel>();
                                menuModel.IsSystem = true;
                                menuAssemblyModels.Add(new MenuAssemblyModel()
                                {
                                    MenuName = menuModel.Title,
                                    Model = menuModel,
                                    MenuAssembly = assemblie
                                });
                            }
                        }
                        catch (Exception ex)
                        {
                            _containerExtension.Resolve<IDialogHost>().DialogShow($"插件加载异常：{ex}", Core.Enums.LogLevel.Error);
                            return;
                        }
                    }
                }
            }
            Menus.Clear();
            List<MenuModel> menus = new List<MenuModel>();
            var loginuser = _containerExtension.Resolve<IUserEntity>().GetLoginUser();
            var roleManage = _containerExtension.Resolve<IUIRoleManage>();
            foreach (var item in menuAssemblyModels)
            {
                item.Model.Title = LangManager.Instance.Lang[item.Model.TitleLang];
                _roleManage.AddUIRole(new Core.Models.UIRoleModel() { Level = 1, Title = item.Model.TitleLang, Name = null, });
                var types = item.MenuAssembly.GetTypes().Where(t => t.IsClass && t.GetCustomAttribute<MenuAttribute>() != null).ToList();
                if (loginuser != null && loginuser.Role.Name != "超级管理员" && loginuser.Role.Name != "管理员")
                {
                    var role = roleManage.GetUIRoleModel(x => x.Level == 1 && x.Title == item.Model.TitleLang && string.IsNullOrEmpty(x.Name));
                    if (role == null || !role.GuidRoles.Any(x => x.Id == loginuser.Role.Id))
                    {
                        continue;
                    }
                }
                List<WPF.Models.MenuItemModel> menuItems = new List<MenuItemModel>();
                foreach (var view in types)
                {
                    var attribute = view.GetCustomAttribute<MenuAttribute>();
                    _roleManage.AddUIRole(new Core.Models.UIRoleModel() { Level = 1, Title = item.Model.TitleLang, Name = attribute.RegionName, });
                    if (loginuser != null && loginuser.Role.Name != "超级管理员" && loginuser.Role.Name != "管理员")
                    {
                        var role = roleManage.GetUIRoleModel(x => x.Level == 1 && x.Title == item.Model.TitleLang && attribute.RegionName == x.Name);
                        if (role == null || !role.GuidRoles.Any(x => x.Id == loginuser.Role.Id))
                        {
                            continue;
                        }
                    }
                    if (loginuser != null && loginuser.Role.Name != "超级管理员" && (
                        attribute.RegionName == "InteractiveSignal"
                        || attribute.RegionName == "SystemConfigParameter"))
                    {
                        continue;
                    }
                    menuItems.Add(new WPF.Models.MenuItemModel()
                    {
                        Index = attribute.Index,
                        Name = attribute.RegionName,
                        IsSystem = true,
                        View = view,
                        ViewModel = item.MenuAssembly.GetType($"{view.Namespace.Replace("Views", "ViewModels")}.{view.Name}ViewModel"),
                    });
                }
                menuItems.Sort((x, y) => x.CompareTo(y));
                menus.Add(new MenuModel() { 
                    Childrens = new ObservableCollection<MenuItemModel>(menuItems),
                    Index = item.Model.Index,
                    IsSystem = true,
                    PackIcon = item.Model.PackIcon,
                    Title = item.Model.Title,
                    TitleLang = item.Model.TitleLang,
                });
            }
            _roleManage.Save();
            UpdateMenu(menus);
        }

        private void UpdateMenu(List<MenuModel> menus)
        { 
            menus.Sort((x, y) => x.CompareTo(y));
            foreach (var item in menus)
            {
                Menus.Add(item);
            }        
        }

        private bool Update()
        {
            var pluginManager = _containerExtension.Resolve<Core.Manager.IPluginManager>();
            var starryEdgeLog = _containerExtension.Resolve<IStarryEdgeLog>();
            var dialogHost = _containerExtension.Resolve<IDialogHost>();
            try
            {
                List<IPlugin> plugins = pluginManager.GetPlugins(x => x.PluginInfo.Type == 1);
                foreach (var plugin in plugins) 
                { 
                    Assembly assembly = plugin.LoadPlugin(starryEdgeLog);
                    var parameter = assembly.GetTypes().Where(t => t.IsClass && typeof(StarryEdge.WPF.Models.MenuModel).IsAssignableFrom(t)).ToList();
                    if (parameter.Count > 0)
                    {
                        StarryEdge.WPF.Models.MenuModel menuModel = Activator.CreateInstance(parameter[0]) as StarryEdge.WPF.Models.MenuModel;
                        var menu_object = menuAssemblyModels.FirstOrDefault(x => x.Model.TitleLang == menuModel.TitleLang);
                        if (menu_object != null)
                        {
                            menu_object.MenuAssembly = assembly;
                            menu_object.Model = menuModel;
                            continue;
                        }
                        Application.Current.Dispatcher.Invoke(() =>
                        {
                            menuModel.Childrens = new ObservableCollection<WPF.Models.MenuItemModel>();
                        });
                        menuAssemblyModels.Add(new MenuAssemblyModel()
                        {
                            MenuName = menuModel.Title,
                            Model = menuModel,
                            MenuAssembly = assembly
                        });
                    }
                }
                Application.Current.Dispatcher.Invoke(() => { Init(); DisplayFirstView(); });
                MessageEventModel message = new MessageEventModel
                {
                    Code = 200,
                    Message = "View",
                    Data = new Dictionary<string, object>() { { "View", default } }
                };
                _aggregator.GetEvent<MessageEvent>().Publish(message);
                return true;
            }
            catch (Exception ex)
            {
                dialogHost.DialogShow($"更新菜单异常：{ex}", Core.Enums.LogLevel.Error, hostDialog:Core.Enums.PopUpTypes.Global);
            }
            return false;
        }
    }
}
